package cn.sdstudio.config;

import cn.sdstudio.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * @author zyq
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class JwtTokenFilter extends OncePerRequestFilter {

    private final JwtUtils jwtUtils;

    private final UserDetailsService userDetailsService;

    private static final String PREFIX = "Bearer ";


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");

        log.info("Authorization header: {}", authHeader);


        if (!StringUtils.hasText(authHeader) || !authHeader.startsWith(PREFIX)) {
            log.info("JWT Token 不是以 Bearer 开头或者不存在，直接进入下一个过滤器。");
            filterChain.doFilter(request, response);
            return;
        }

        // 移除 "Bearer " 前缀
        String token = authHeader.substring(7);

        try {
            //解析jwt token
            Claims claims = jwtUtils.parseToken(token);

            // 1. 从JWT的 "username" 声明中获取真实的用户名
            String usernameForLookup = claims.get("username", String.class);
            if (usernameForLookup == null) {
                log.error("JWT Token 中不包含 'username' 声明。");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("{\"error\": \"无效的Token\", \"message\": \"Token中缺少username声明\"}");
                return;
            }

            // 2. 从 "sub" (subject) 声明中获取用户ID字符串
            String userIdFromSubject = claims.getSubject();
            log.info("Token Subject (作为用户ID字符串): {}", userIdFromSubject);
            log.info("用于UserDetailsService查询的username声明: {}", usernameForLookup);


            // 3. 检查认证信息是否已存在 (例如，来自前一个过滤器或会话)
            //    对于纯粹基于Token的认证，通常每次都会重新验证Token。
            if (SecurityContextHolder.getContext().getAuthentication() == null) {
                // 使用提取到的真实用户名 ("user") 来加载用户详情
                var userDetails = userDetailsService.loadUserByUsername(usernameForLookup);

                // 创建认证凭证
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

                // 可选：设置 details。通常的做法是设置 WebAuthenticationDetails。
                // 如果你想将Token中的用户ID设置为details：
                try {
                    Long parsedUserId = Long.parseLong(userIdFromSubject);
                    authentication.setDetails(parsedUserId);
                    log.info("已将解析后的用户ID设置到认证details中: {}", parsedUserId);
                } catch (NumberFormatException e) {
                    log.warn("无法将Token subject中的用户ID '{}' 解析为Long类型。", userIdFromSubject);
                }

                SecurityContextHolder.getContext().setAuthentication(authentication);
                log.info("用户 '{}' 已通过JWT成功认证。", usernameForLookup);
            } else {
                log.info("SecurityContextHolder 中已存在认证信息: '{}'", SecurityContextHolder.getContext().getAuthentication().getName());
            }

        } catch (JwtException e) {
            log.error("JWT 解析或验证失败: {}", e.getMessage());
            // JWT错误时显式清除上下文，防止未认证用户意外获取访问权限
            SecurityContextHolder.clearContext();
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"error\": \"未授权\", \"message\": \"无效或已过期的JWT Token\"}");
            return;
        } catch (Exception e) {
            log.error("处理JWT Token过程中发生错误: {}", e.getMessage(), e);
            SecurityContextHolder.clearContext();
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"error\": \"服务器内部错误\", \"message\": \"处理Token时发生错误\"}");
            return;
        }
        filterChain.doFilter(request, response);
    }

}
